package com.example.thirdjarlearningcore.postProcessor;

import com.example.thirdjarlearningcore.annotation.ThirdJarCotAsBean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.core.type.filter.AnnotationTypeFilter;

import java.util.Arrays;
import java.util.Set;

/**
 * 自定义的 scanner，需要继承 ClassPathBeanDefinitionScanner 类
 * 同样，这个类没有任何的 @Component注解
 */
public class ThirdJarCatAsBeanScanner extends ClassPathBeanDefinitionScanner {

    private final Logger LOGGER = LoggerFactory.getLogger(ThirdJarCatAsBeanScanner.class);

    // 该类需要一个构造函数，
    public ThirdJarCatAsBeanScanner(BeanDefinitionRegistry registry) {
        super(registry, false);
    }

    /**
     * 核心内容
     * @param basePackages
     * @return
     */
    @Override
    protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
        // 添加扫描条件--只扫描带有 @ThirdJarCotAsBean 的注解
        addIncludeFilter(new AnnotationTypeFilter(ThirdJarCotAsBean.class));
        /**
         * 调用父类的doScan方法
         * 一个很重要的理解点是，去看父类的doScan源码发现，doScan本身就会把扫描到的类直接做成BeanDefinition
         * 只不过最后也会返回一个制作成集合的 Set<BeanDefinition>
         */
        Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);
        // 如果父类doScan的返回值非空，则说明至少有一个带有 @ThirdJarCotAsBean 的类被扫描到
        if (!beanDefinitions.isEmpty()) {
            // 注意此时容器中已经有了所有 @ThirdJarCotAsBean 注解的类的BeanDefinition，下面这个函数只是把他们进行一些修改
            // 另外，再次强调，这里的容器是core的容器，不是starter的容器，更不是use的容器
            try {
                processBeanDefinitions(beanDefinitions);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        } else {
            LOGGER.info("No Annotation was found in '" + Arrays.toString(basePackages)
                    + "' package with name '@ThirdJarCotAsBean'");
        }
        return beanDefinitions;
    }

    /**
     * 在上面的方法中被调用。对已经存在 BeanDefinition进行修改
     * @param beanDefinitions
     * @throws ClassNotFoundException
     */
    private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) throws ClassNotFoundException {
        GenericBeanDefinition definition;
        for (BeanDefinitionHolder holder : beanDefinitions) {
            definition = (GenericBeanDefinition) holder.getBeanDefinition();
            String beanClassName = definition.getBeanClassName();

            LOGGER.info("Configuring BeanDefinition with name '" + holder.getBeanName() + "' and '" + beanClassName + "'");

            // 其实就是根据 @ThirdJarCotAsBean 属性的值，对 BeanDefinition进行一些修改，例如这里就是根据 @ThirdJarCotAsBean 是否为单例进行修改
            Class<?> tarClass = Class.forName(beanClassName);
            ThirdJarCotAsBean tarClassAnnotation = tarClass.getAnnotation(ThirdJarCotAsBean.class);
            definition.setScope(tarClassAnnotation.isSingleton() ? BeanDefinition.SCOPE_SINGLETON : BeanDefinition.SCOPE_PROTOTYPE);
            // definition.getPropertyValues().add("ScannerAddProperty", "ScannerAddPropertyValue");
        }
    }
}
